﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Windows.Controls;
using Syncfusion.Pdf;
using Syncfusion.Windows.PdfViewer;

namespace PdfSdk.PdfViewer
{
    public class PdfDocumentViewWrapper : ObjectWrapper
    {
        public static readonly Type s_pdfViewerActionTypeType;
        public static readonly Type s_pdfViewerShapeAnnotationMode;

        static PdfDocumentViewWrapper()
        {
            Type type = typeof(PdfDocumentView);

            s_pdfViewerActionTypeType = type.GetNestedType("PdfViewerActionType", BindingFlags.NonPublic);
            s_pdfViewerShapeAnnotationMode = type.GetNestedType("PdfViewerShapeAnnotationMode", BindingFlags.NonPublic);
        }

        internal PdfDocumentViewWrapper(PdfDocumentView documentView) : base(documentView)
        {
        }

        public IPdfControl PdfControl { get; set; }

        #region IPdfViewer

        public IPdfViewer PdfViewer { get; set; }

        #endregion

        #region Custom

        public bool AreaSelectionEnabled { get; set; }
        public Action<SelectionCanvasWrapper, System.Windows.Rect> AreaSelectionCallback;

        public bool InkStraightEnabled { get; set; }

        public bool IsEditingEnabled { get; set; }

        #endregion

        public PdfDocumentView PdfDocumentView => _originalObject as PdfDocumentView;

        public DocumentView innerPanel => GetFieldValue() as DocumentView;

        public Stream m_printStream
        {
            get => GetFieldValue() as Stream;
            set => SetFieldValue(value);
        }

        public System.Drawing.Printing.PrintDocument PrintingDocument => GetPropertyValue() as System.Drawing.Printing.PrintDocument;

        public IntPtr Document
        {
            get => (IntPtr)GetFieldValue();
            set => SetFieldValue(value);
        }

        public int m_documentID
        {
            get => Convert.ToInt32(GetFieldValue());
            set => SetFieldValue(value);
        }

        public bool m_isPopupFocused => Convert.ToBoolean(GetFieldValue());

        public bool isMultipleTimesLoaded => Convert.ToBoolean(GetFieldValue());

        public PdfViewerFreeTextAnnotationWrapper m_focusedFreeTextAnnotation
        {
            get
            {
                var obj = GetFieldValue();
                if (obj != null)
                {
                    return new PdfViewerFreeTextAnnotationWrapper(obj);
                }
                return null;
            }
            set => SetFieldValue(value);
        }

        public ScrollViewer ScrollViewer => GetPropertyValue() as ScrollViewer;

        public PdfViewerInkAnnotationMode InkMode => (PdfViewerInkAnnotationMode)Convert.ToInt32(GetPropertyValue());

        public PdfViewerTextMarkupAnnotationMode TextMarkupMode => (PdfViewerTextMarkupAnnotationMode)Convert.ToInt32(GetPropertyValue());
        public PdfViewerShapeAnnotationMode ShapeMode => (PdfViewerShapeAnnotationMode)Convert.ToInt32(GetPropertyValue());
        public bool IsPanning => Convert.ToBoolean(GetPropertyValue());
        public bool IsPanTouchedDown => Convert.ToBoolean(GetPropertyValue());
        public bool IsStandardStampSelected => Convert.ToBoolean(GetPropertyValue());
        public bool IsCustomImageSelected => Convert.ToBoolean(GetPropertyValue());

        public void OnPageMouseMove(PageMouseMoveEventArgs eventArgs) => InvokeMethod("OnPageMouseMove", eventArgs);

        internal void OnPageClicked(PageClickedEventArgs eventArgs) => InvokeMethod("OnPageClicked", eventArgs);

        public Action<int, InkCanvas> PageClickedEx;

        internal void OnPageClickedEx(int pageIndex, InkCanvas canvas)
        {
            PageClickedEx?.Invoke(pageIndex, canvas);
        }

        internal void OnHandWrittenSignatureChanged(HandwrittenSignatureChangedEventArgs e) => InvokeMethod("OnHandWrittenSignatureChanged", e);

        internal void HideFontPopUp()
        {
            if (m_focusedFreeTextAnnotation != null)
            {
                if (!m_focusedFreeTextAnnotation.TextBox.IsReadOnly)
                    m_focusedFreeTextAnnotation.TextBox.IsReadOnly = true;
                m_focusedFreeTextAnnotation = null;
            }
            if (innerPanel.GetWrapper().zoomChangedFreeTextAnnotation != null)
                innerPanel.GetWrapper().zoomChangedFreeTextAnnotation = null;
        }

        public void RotatePage(int index, PdfPageRotateAngle rotateAngle)
        {
            InvokeMethod("RotatePage", index, rotateAngle);
        }

        public void RemovePages(int[] pageIndexes)
        {
            InvokeMethod("RemovePages", pageIndexes);
        }

        public void CreatePDFiumDocument(Stream fileStream, string password)
        {
            InvokeMethod("CreatePDFiumDocument", fileStream, password);
        }

        public void ReloadPdfiumDocument() => InvokeMethod();

        public void ClearSelectedAnnotation()
        {
            InvokeMethod();
        }

        public void UnloadEx()
        {
            Dictionary<int, Stream> files = StreamManager._files;
            if (files == null)
            {
                return;
            }

            PdfDocumentView documentView = (PdfDocumentView)_originalObject;
            int documentID = documentView.GetWrapper().m_documentID;

            lock (StreamManager.LockerEx)
            {
                Dictionary<int, Stream> backupFiles = new();
                foreach (var kv in files)
                {
                    if (kv.Key != documentID)
                    {
                        backupFiles.Add(kv.Key, kv.Value);
                    }
                }
                files.Clear();

                try
                {
                    documentView.Unload(true);
                }
                finally
                {
                    foreach (var kv in backupFiles)
                    {
                        files.Add(kv.Key, kv.Value);
                    }
                    backupFiles.Clear();
                }
            }
        }

        public enum PdfViewerTextMarkupAnnotationMode
        {
            None,
            Highlight,
            Underline,
            Strikethrough,
        }

        public enum PdfViewerActionType
        {
            Add,
            Remove,
            MoveOrResize,
            PropertyChange,
            None,
            Layer,
            Hide,
            Show,
        }

        public enum PdfViewerShapeAnnotationMode
        {
            None,
            Line,
            Rectangle,
            Circle,
            Arrow,
            Polyline,
        }

        public enum PdfViewerInkAnnotationMode
        {
            None,
            Ink,
        }

        public enum PdfViewerFreeTextAnnotationMode
        {
            None,
            FreeText,
        }

        public enum PdfViewerAnnotationMode
        {
            None,
            Ink,
            Highlight,
            Underline,
            Strikethrough,
            Line,
            Rectangle,
            Circle,
            FreeText,
            Stamp,
            HandwrittenSignature,
            StickyNote,
            Polygon,
            Polyline,
            InkEraser,
        }

        public void SetAnnotationModeForShapeEx(PdfDocumentView.PdfViewerAnnotationMode value)
        {
            SetFieldValue(value, "m_annotationMode");
            InvokeMethod("ResetModes");

            if (value == PdfDocumentView.PdfViewerAnnotationMode.Circle)
                SetPropertyValue(Enum.Parse(s_pdfViewerShapeAnnotationMode, "Circle"), "ShapeMode");
            else if (value == PdfDocumentView.PdfViewerAnnotationMode.Line)
                SetPropertyValue(Enum.Parse(s_pdfViewerShapeAnnotationMode, "Line"), "ShapeMode");
            else if (value == PdfDocumentView.PdfViewerAnnotationMode.Rectangle)
                SetPropertyValue(Enum.Parse(s_pdfViewerShapeAnnotationMode, "Rectangle"), "ShapeMode");
            else
                return;

            SetPropertyValue(false, "IsStandardStampSelected");
            SetPropertyValue(false, "IsCustomImageSelected");

            innerPanel.GetWrapper().ChangeCanvasModeNotClearSelectionEx();

            InvokeMethod("CheckSelectedStamp");
        }
    }
}
